package framework.utils;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.fasterxml.jackson.annotation.JsonFormat.Feature;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonSerialize.Inclusion;

@SuppressWarnings("unchecked")
public class JackSonUtil {

	private static ObjectMapper MAPPER;

	static {
		MAPPER = generateMapper(Inclusion.ALWAYS);
	}

	private JackSonUtil() {
	}

	/**
	 * 将json通过类型转换成对象
	 * 
	 * <pre>
	 *     {@link JsonUtil JsonUtil}.fromJson("{\"username\":\"username\", \"password\":\"password\"}", User.class);
	 * </pre>
	 * 
	 * @param json
	 *            json字符串
	 * @param clazz
	 *            泛型类型
	 * @return 返回对象
	 * @throws IOException
	 */
	public static <T> T fromJson(String json, Class<T> clazz) throws IOException {
		return clazz.equals(String.class) ? (T) json : MAPPER.readValue(json, clazz);
	}
	
	 

	/**
	 * 将json通过类型转换成对象
	 * 
	 * <pre>
	 *     {@link JsonUtil JsonUtil}.fromJson("[{\"username\":\"username\", \"password\":\"password\"}, {\"username\":\"username\", \"password\":\"password\"}]", new TypeReference&lt;List&lt;User&gt;&gt;);
	 * </pre>
	 * 
	 * @param json
	 *            json字符串
	 * @param typeReference
	 *            引用类型
	 * @return 返回对象
	 * @throws IOException
	 */
	public static <T> T fromJson(String json, TypeReference<?> typeReference) throws IOException {
		if(StringUtils.isNullOrBlank(json)){
			return  null;
		}
		return (T) (typeReference.getType().equals(String.class) ? json : MAPPER.readValue(json, typeReference));
	}
	
	/**
	 * 将json转成List集合对象, json为空或null 返回空数组（非null）
	 * @Title: jsonToList
	 * @Description: 
	 * @author li.quan
	 * @date 2016-7-18 下午05:03:11
	 * @param <E>
	 * @param json
	 * @param clazz
	 * @return
	 * @throws IOException    
	 * @return E
	 */
	public static <E> E jsonToList(String json, Class<? extends List> clazz) throws IOException {
		if(StringUtils.isNullOrBlank(json)){
			return (E)new ArrayList<E>();
		}
		return  (E)MAPPER.readValue(json, new TypeReference<List<E>>() {});
	}
 
	/**
	 * 将json转成Map集合对象，json为空或null 返回空集合（非null）
	 * @Title: jsonToMap
	 * @Description: 
	 * @author li.quan
	 * @date 2016-7-18 下午05:18:29
	 * @param <E>
	 * @param json
	 * @param clazz
	 * @return
	 * @throws IOException    
	 * @return E
	 */
	public static <E> E jsonToMap(String json, Class<? extends Map> clazz) throws IOException {
		if(StringUtils.isNullOrBlank(json)){
			return (E)new HashMap();
		}
		return  (E)MAPPER.readValue(json, new TypeReference<Map>() {});
	}

	/**
	 * 将对象转换成json
	 * 
	 * <pre>
	 *     {@link JsonUtil JsonUtil}.toJson(user);
	 * </pre>
	 * 
	 * @param src
	 *            对象
	 * @return 返回json字符串
	 * @throws IOException
	 */
	public static <T> String toJson(T src) throws IOException {
		return src instanceof String ? (String) src : MAPPER.writeValueAsString(src);
	}

	/**
	 * 将对象转换成json, 可以设置输出属性
	 * 
	 * <pre>
	 *     {@link JsonUtil JsonUtil}.toJson(user, {@link Inclusion Inclusion.ALWAYS});
	 * </pre>
	 * 
	 * {@link Inclusion Inclusion 对象枚举}
	 * <ul>
	 * <li>{@link Inclusion Inclusion.ALWAYS 全部列入}</li>
	 * <li>{@link Inclusion Inclusion.NON_DEFAULT 字段和对象默认值相同的时候不会列入}</li>
	 * <li>{@link Inclusion Inclusion.NON_EMPTY 字段为NULL或者""的时候不会列入}</li>
	 * <li>{@link Inclusion Inclusion.NON_NULL 字段为NULL时候不会列入}</li>
	 * </ul>
	 * 
	 * @param src
	 *            对象
	 * @param inclusion
	 *            传入一个枚举值, 设置输出属性
	 * @return 返回json字符串
	 * @throws IOException
	 */
	public static <T> String toJson(T src, Inclusion inclusion) throws IOException {
		if (src instanceof String) {
			return (String) src;
		} else {
			ObjectMapper customMapper = generateMapper(inclusion);
			return customMapper.writeValueAsString(src);
		}
	}

	/**
	 * 将对象转换成json, 传入配置对象
	 * 
	 * <pre>
	 *     {@link ObjectMapper ObjectMapper} mapper = new ObjectMapper();
	 *     mapper.setSerializationInclusion({@link Inclusion Inclusion.ALWAYS});
	 *     mapper.configure({@link Feature Feature.FAIL_ON_UNKNOWN_PROPERTIES}, false);
	 *     mapper.configure({@link Feature Feature.FAIL_ON_NUMBERS_FOR_ENUMS}, true);
	 *     mapper.setDateFormat(new {@link SimpleDateFormat SimpleDateFormat}("yyyy-MM-dd HH:mm:ss"));
	 *     {@link JsonUtil JsonUtil}.toJson(user, mapper);
	 * </pre>
	 * 
	 * {@link ObjectMapper ObjectMapper}
	 * 
	 * @see ObjectMapper
	 * 
	 * @param src
	 *            对象
	 * @param mapper
	 *            配置对象
	 * @return 返回json字符串
	 * @throws IOException
	 */
	public static <T> String toJson(T src, ObjectMapper mapper) throws IOException {
		if (null != mapper) {
			if (src instanceof String) {
				return (String) src;
			} else {
				return mapper.writeValueAsString(src);
			}
		} else {
			return null;
		}
	}

	/**
	 * 返回{@link ObjectMapper ObjectMapper}对象, 用于定制性的操作
	 * 
	 * @return {@link ObjectMapper ObjectMapper}对象
	 */
	public static ObjectMapper mapper() {
		return MAPPER;
	}

	/**
	 * 通过Inclusion创建ObjectMapper对象
	 * 
	 * {@link Inclusion Inclusion 对象枚举}
	 * <ul>
	 * <li>{@link Inclusion Inclusion.ALWAYS 全部列入}</li>
	 * <li>{@link Inclusion Inclusion.NON_DEFAULT 字段和对象默认值相同的时候不会列入}</li>
	 * <li>{@link Inclusion Inclusion.NON_EMPTY 字段为NULL或者""的时候不会列入}</li>
	 * <li>{@link Inclusion Inclusion.NON_NULL 字段为NULL时候不会列入}</li>
	 * </ul>
	 * 
	 * @param inclusion
	 *            传入一个枚举值, 设置输出属性
	 * @return 返回ObjectMapper对象
	 */
	private static ObjectMapper generateMapper(Inclusion inclusion) {

		ObjectMapper customMapper = new ObjectMapper();

//		// 设置输出时包含属性的风格
//		customMapper.setSerializationInclusion(inclusion);
//
//		// 设置输入时忽略在JSON字符串中存在但Java对象实际没有的属性
//		customMapper.configure(Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
//
//		// 禁止使用int代表Enum的order()來反序列化Enum,非常危險
//		customMapper.configure(Feature.FAIL_ON_NUMBERS_FOR_ENUMS, true);

		// 所有日期格式都统一为以下样式
		customMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"));

		return customMapper;
	}
}
